package com.scau402.system1.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.github.pagehelper.PageInfo;
import com.scau402.common.constant.DeptConstants;
import com.scau402.common.core.domain.entity.SysUser;
import com.scau402.common.core.page.TableDataInfo;
import com.scau402.common.enums.outbound.OutboundType;
import com.scau402.common.exception.ServiceException;
import com.scau402.common.utils.*;
import com.scau402.common.utils.code.OutboundOrderCodeUtils;
import com.scau402.system.mapper.WmsInboundOrderMapper;
import com.scau402.system.service.ISysTenantService;
import com.scau402.system1.domain.factory.WmsOutboundOrderFactory;
import com.scau402.system1.repository.IWmsOutboundOrderRepository;
import com.scau402.system1.service.IWmsOutboundOrderDetailService;
import com.scau402.system1.domain.po.WmsOutboundOrderDO;
import com.scau402.system1.domain.po.WmsOutboundOrderDetailDO;
import com.scau402.system1.domain.query.WmsOutboundOrderQuery;
import com.scau402.system1.domain.vo.WmsOutboundOrderDetailVO;
import com.scau402.system1.domain.vo.WmsOutboundOrderAndDetailVO;
import com.scau402.system1.mapper.IWmsOutboundOrderDetailMapper;
import com.scau402.system1.mapper.IWmsOutboundOrderMapper;
import com.scau402.system1.service.IWmsOutboundOrderService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 商品出库单主表 服务实现类
 * </p>
 *
 * @author
 * @since 2023-12-23
 */
@Service
@Slf4j
public class IWmsOutboundOrderServiceImpl extends ServiceImpl<IWmsOutboundOrderMapper, WmsOutboundOrderDO> implements IWmsOutboundOrderService {

    @Autowired
    private IWmsOutboundOrderMapper wmsOutboundOrderMapper;

    @Autowired
    private IWmsOutboundOrderDetailService wmsOutboundOrderDetailService;

    @Autowired
    private IWmsOutboundOrderDetailMapper wmsOutboundOrderDetailMapper;

    @Autowired
    private ISysTenantService tenantService;

    @Autowired
    private WmsOutboundOrderFactory wmsOutboundOrderFactory;
    @Autowired
    private IWmsOutboundOrderRepository outboundOrderRepo;

    @Autowired
    private WmsInboundOrderMapper wmsInboundOrderMapper;
    @Override
    public String getNewCode(SysUser user) throws InterruptedException {
        // 获取数据库中最大的编码
        String maxCode = getMaxCode();
        String userCode = user.getUserCode();

        // 返回maxCode为NULL，及当前数据库没有数据，从0开始
        if (StringUtils.isNull(maxCode)) {
            maxCode = "0";
        }

        // 获取当前用户所属租户编码
        Long loginUserTenantId = SecurityUtils.getLoginUser().getTenantId();
        String loginUserTenantCode = tenantService.selectSysTenantByTenantId(loginUserTenantId).getTenantCode();

        // 设置redis的当前编码
        OutboundOrderCodeUtils outboundOrderCodeUtils = new OutboundOrderCodeUtils();
        outboundOrderCodeUtils.setCurrentCodeToMax(maxCode, loginUserTenantCode, userCode);

        return getOutboundOrderCode(loginUserTenantCode, userCode);
    }

    @Override
    public String getMaxCode() {
        Long tenantId = SecurityUtils.getLoginUser().getTenantId();
        String userCode = SecurityUtils.getLoginUser().getUser().getUserCode();
        userCode = userCode.substring(1);
        Map<String, Object> params = new HashMap<>();
        // 设置参数值
        params.put("tenantId", tenantId);
        params.put("userCode", userCode);
        return wmsOutboundOrderMapper.getMaxCode(params);
    }

    /**
     * 检查单号是否存在
     * @param currentOrderCode 当前单号
     * @return 检查结果
     */
    @Override
    public boolean checkOrderCodeExist(String currentOrderCode) {
        int i = wmsOutboundOrderMapper.checkOrderCodeExist(currentOrderCode);
        return i > 0;
    }

    @Override
    public String getOutboundOrderCode(String loginUserTenantCode, String userCode) throws InterruptedException {
        OutboundOrderCodeUtils outboundOrderCodeUtils = new OutboundOrderCodeUtils();
        return OutboundOrderCodeUtils.getNewCode(loginUserTenantCode, userCode);
    }


    @Override
    public TableDataInfo selectWmsOutboundOrderListPage(WmsOutboundOrderQuery query) {
        log.info("查询出库单列表，参数：{}", query);
        query.setTenantId(SecurityUtils.getLoginUser().getTenantId());
        // 分页
        PageUtils.startPage();
        List<WmsOutboundOrderDO> wmsOutboundOrderDOs = wmsOutboundOrderMapper.selectWmsOutboundOrderList(query);
        // wmsOutboundOrderDOs是Page类型携带分页信息的，需要将分页信息设置到MDC中
        PageInfo<WmsOutboundOrderDO> pageInfo = new PageInfo<>(wmsOutboundOrderDOs);
        PageUtils.fetchSessionPageInfo(pageInfo);
        if (DataUtils.isEmpty(wmsOutboundOrderDOs)) {
            log.warn("查询出库单列表为空,参数：{}", query);
            return new TableDataInfo();
        }

        List<String> orderCodeList = wmsOutboundOrderDOs.stream()
                .filter(Objects::nonNull)
                .map(WmsOutboundOrderDO::getOrderCode).collect(Collectors.toList());
        //查询明细信息
        List<WmsOutboundOrderAndDetailVO> wmsOutboundOrderAndDetailVOs = getWmsOutboundOrderVOS(wmsOutboundOrderDOs, orderCodeList);
        return PageUtils.getDataTableFrom2Lists(wmsOutboundOrderAndDetailVOs, wmsOutboundOrderDOs);
    }

    private List<WmsOutboundOrderAndDetailVO> getWmsOutboundOrderVOS(List<WmsOutboundOrderDO> wmsOutboundOrderDOS, List<String> orderCodeList) {
        if (DataUtils.isEmpty(wmsOutboundOrderDOS)) {
            return new ArrayList<>();
        }
        if (DataUtils.isEmpty(orderCodeList)) {
            log.warn("出库单号为空");
        }
        List<WmsOutboundOrderDetailVO> wmsOutboundOrderDetailVOS = DataUtils.isEmpty(orderCodeList) ? new ArrayList<>(0) : wmsOutboundOrderDetailService.listDetailVO(orderCodeList);
        //过滤null数据，收集并按组保存
        Map<String, List<WmsOutboundOrderDetailVO>> collect = wmsOutboundOrderDetailVOS.stream()
                .filter(Objects::nonNull)
                .collect(Collectors.groupingBy(WmsOutboundOrderDetailVO::getOutboundOrderCode));
        return wmsOutboundOrderDOS.stream()
                .filter(Objects::nonNull)
                .map(x -> {
                    WmsOutboundOrderAndDetailVO wmsOutboundOrderAndDetailVO = new WmsOutboundOrderAndDetailVO();
                    wmsOutboundOrderAndDetailVO.setDetailVOS(Optional.ofNullable(collect.get(x.getOrderCode())).orElse(new ArrayList<>(0)));
                    //设置出库总数
                    x.setOutboundSumCount((long) Optional.ofNullable(collect.get(x.getOrderCode())).orElse(new ArrayList<>(0)).size());
                    wmsOutboundOrderAndDetailVO.setWmsOutboundOrderVo(wmsOutboundOrderFactory.toWmsOutboundOrderVo(x));
                    return wmsOutboundOrderAndDetailVO;
                }).collect(Collectors.toList());
    }

    @Override
    public void merge(List<Long> outboundOrderIds) throws InterruptedException {
        List<WmsOutboundOrderDO> wmsOutboundOrderDOS = wmsOutboundOrderMapper.selectList(
                new LambdaQueryWrapper<WmsOutboundOrderDO>()
                        .in(WmsOutboundOrderDO::getId, outboundOrderIds)
        );

        // 检查是否满足合并要求  TODO: 后续需要支持其他的出库单合并改动这部分就可以了
        if (CollectionUtils.isEmpty(wmsOutboundOrderDOS)) {
            throw new ServiceException("销售出库单为空");
        }
        boolean match = wmsOutboundOrderDOS.stream()
                .allMatch(item -> org.apache.commons.lang3.StringUtils.equals(item.getOrderType(), OutboundType.SALE.getCode()));
        if (!match) {
            throw new ServiceException("仅支持合并销售出库单");
        }
        Set<Long> supplierSet = wmsOutboundOrderDOS.stream()
                .map(WmsOutboundOrderDO::getClientId)
                .collect(Collectors.toSet());
        if (CollectionUtils.isEmpty(supplierSet) || supplierSet.size() != 1) {
            throw new ServiceException("仅支持合并同一个客户的销售出库单");
        }

        // 拿到第一条的数据，以第一条的入库单数据为准
        WmsOutboundOrderDO one = Objects.requireNonNull(CollectionUtils.firstElement(wmsOutboundOrderDOS));
        WmsOutboundOrderDO wmsOutboundOrderDO = new WmsOutboundOrderDO();
        String newCode = getNewCode(SecurityUtils.getLoginUser().getUser());
        wmsOutboundOrderDO.setOrderCode(newCode);
        wmsOutboundOrderDO.setOrderType(one.getOrderType());
        wmsOutboundOrderDO.setDeptId(DeptConstants.DEPT_ID_DEFAULT);
        wmsOutboundOrderDO.setClientId(one.getClientId());
        wmsOutboundOrderDO.setWarehouseId(one.getWarehouseId());
        wmsOutboundOrderDO.setDelFlag("0");
        wmsOutboundOrderDO.setCreateBy(SecurityUtils.getLoginUser().getUsername());
        wmsOutboundOrderDO.setUpdateBy(SecurityUtils.getLoginUser().getUsername());
        wmsOutboundOrderDO.setCreateTime(DateUtils.getNowDate());
        wmsOutboundOrderDO.setUpdateTime(DateUtils.getNowDate());
        wmsOutboundOrderDO.setRemark(one.getRemark());
        wmsOutboundOrderDO.setTenantId(SecurityUtils.getLoginUser().getUser().getTenantId());
        wmsOutboundOrderDO.setSupplierId(one.getSupplierId());
        wmsOutboundOrderDO.setSettleBy(one.getSettleBy());
        wmsOutboundOrderDO.setSettlementType(one.getSettlementType());
        wmsOutboundOrderDO.setSettlementRatio(one.getSettlementRatio());
        wmsOutboundOrderDO.setIsSettle(one.getIsSettle());
        wmsOutboundOrderDO.setOrderBatch(one.getOrderBatch());
        wmsOutboundOrderMapper.insert(wmsOutboundOrderDO);

        // 将原有的出库明细指向新的出库单
        // 保险一点的做法应该是将旧的明细删除，复制一份新的明细关联新的出库单
        wmsOutboundOrderDetailMapper.update(
                null,
                new LambdaUpdateWrapper<WmsOutboundOrderDetailDO>()
                        .in(
                                WmsOutboundOrderDetailDO::getOutboundOrderCode,
                                wmsOutboundOrderDOS.stream()
                                        .map(WmsOutboundOrderDO::getOrderCode)
                                        .collect(Collectors.toList())
                        )
                        .set(WmsOutboundOrderDetailDO::getOutboundOrderCode, newCode)

        );

        // 删除旧的入库单
        wmsOutboundOrderMapper.update(
                null,
                new LambdaUpdateWrapper<WmsOutboundOrderDO>()
                        .in(
                                WmsOutboundOrderDO::getId,
                                wmsOutboundOrderDOS.stream()
                                        .map(WmsOutboundOrderDO::getId)
                                        .collect(Collectors.toList())
                        )
                        .set(WmsOutboundOrderDO::getDelFlag, "2")   //设置删除标记
        );
    }

    /**
     * 根据出库单查询实体类搜索出库单信息
     * @param query
     * @return
     */
    @Override
    public List<WmsOutboundOrderAndDetailVO> selectWmsOutboundOrderListByCodes(WmsOutboundOrderQuery query) {
        List<WmsOutboundOrderDO> wmsOutboundOrderDOS = wmsOutboundOrderMapper.selectWmsOutboundOrderList(query);
        List<String> orderCodes = query.getOrderCodes();
        return getWmsOutboundOrderVOS(wmsOutboundOrderDOS, orderCodes);
    }


//    @Override
//    public String getInboundTypeOrder(Long inboundOrderId) {
//        String inBoundType=wmsInboundOrderMapper.getInboundTypeName(inboundOrderId);
//        return inBoundType;
//    }

//    @Override
//    public WmsOutboundOrderVO selectOutboundOrderByOrderCode(String outboundOrderCode) {
//        WmsOutboundOrderDO wmsOutboundOrderDO=  wmsOutboundOrderMapper.selectWmsOutboundOrderByOrderCode(outboundOrderCode);
//        List<WmsOutboundOrderDetailVO> detailVOs =wmsOutboundOrderDetailService.listDetailVO(outboundOrderCode);
//        WmsOutboundOrderVO wmsOutboundOrderVO = new WmsOutboundOrderVO();
//        wmsOutboundOrderVO.setWmsOutboundOrderDO(wmsOutboundOrderDO);
//        wmsOutboundOrderVO.setDetailVOS(detailVOs);
//        return wmsOutboundOrderVO;
//    }
}
